package top.dark.product.controller;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * Author: Darkn
 * description:
 * Create Time: 2021/3/10 16:26
 */
@Slf4j
@RequestMapping("/product")
@RestController
public class HelloTestController {

    @Autowired
    private RedissonClient redisson;

    /**
     * 可重入锁，如果已经线程获取锁，则其他线程均阻塞，默认过期时间30秒，
     * 但是如果线程在过期时间到了还未完成任务，并且未设置过期时间，默认使用看门狗机制（lockWatchdogTimeout）进行续约，续约时间是30秒
     */
    @RequestMapping("/hello")
    public String hello() {
        RLock lock = redisson.getLock("lock");
        // 未设置过期时间，则会使用看门狗机制进行续约
        // lock.lock();
        // 设置了过期时间，则不会使用看门狗机制进行续约
        lock.lock(10, TimeUnit.SECONDS);
        try {
            System.out.println("加锁成功，执行业务..." + Thread.currentThread().getId());
            Thread.sleep(300000);
        } catch (Exception e) {
        } finally {
            // 解锁 将设解锁代码没有运行，reidsson会不会出现死锁
            System.out.println("释放锁...." + Thread.currentThread().getId());
            lock.unlock();
        }
        return "hello";
    }

    /**
     * 读写锁(内部机制同可重入锁，如果自定义时间则不是使用看门狗机制)
     * 作用：保证读取到的数据一定是最新的数据
     * 写锁：一个排他锁、互斥锁、独享锁
     * 读锁：共享锁
     */
    @RequestMapping("/write")
    public String writeValue() {
        RReadWriteLock rw_lock = redisson.getReadWriteLock("rw_lock");
        RLock rLock = rw_lock.writeLock();
        rLock.lock();
        try {
            log.info("{}-设置写锁成功，进入写业务。。。。。。", Thread.currentThread().getId());
            Thread.sleep(5000);
        } catch (Exception e) {
        } finally {
            log.info("{}-释放写锁。。。。", Thread.currentThread().getId());
            rLock.unlock();
        }
        return "write ok";
    }

    @RequestMapping("/read")
    public String readValue() {
        RReadWriteLock rw_lock = redisson.getReadWriteLock("rw_lock");
        RLock rLock = rw_lock.readLock();
        rLock.lock(10, TimeUnit.SECONDS);
        try {
            log.info("{}-设置读锁成功，进入读业务。。。。。。。", Thread.currentThread().getId());
            Thread.sleep(50000);
        } catch (Exception e) {
        } finally {
            log.info("{}-释放读锁。。。。。。。", Thread.currentThread().getId());
            rLock.unlock();
        }
        return "read ok";
    }


    /**
     * 闭锁
     */
    @RequestMapping("/lockDoor")
    public String lockDoor() throws InterruptedException {
        RCountDownLatch lockdoor = redisson.getCountDownLatch("lockdoor");
        lockdoor.trySetCount(5);
        lockdoor.await(); // 等待闭锁都完成
        return "放假拉..............";
    }

    @RequestMapping("/gogogo/{id}")
    public String gogogo(@PathVariable("id") Long id) {
        RCountDownLatch lockdoor = redisson.getCountDownLatch("lockdoor");
        lockdoor.countDown();
        return id + "班的人走完了.........";
    }

    /**
     * 信号量
     * 一个信号量对应一个坑，只有释放了对应的量才能让下一个人占用这个坑
     */
    @RequestMapping("/park")
    public String park(){
        RSemaphore park = redisson.getSemaphore("park");
        boolean b = park.tryAcquire(2);
        return "ok=" + b;
    }

    @RequestMapping("/go")
    public String go(){
        RSemaphore park = redisson.getSemaphore("park");
        park.release();
        return "ok";
    }
}
